`timescale 1ns / 1ps
`include "const.v"

`define op instr[31:26]
`define funct instr[5:0]

module MainCtrl(
    input [31:0] instr,
    output [2:0] RinSel,
    output RegWr,
    output [1:0] RegDst,
    output [1:0] PCSrc,
    output [1:0] Eop,
    output [3:0] Aop,
    output ASrc,
    output MemWr,
    output [1:0] store,
    output [2:0] Dop,
    output [2:0] Cop,
    output start,
    output [1:0] Mop,
    output MDCmd,
    output HLWr,
    output MDDst,
    output HLSrc,
    output shmt,
    output ld,
    output st,
    output CP0Wr,
    output eret
    );


    // MDU
    assign start = (`op==`R && (`funct==`MULT ||
                                `funct==`MULTU || 
                                `funct==`DIV || 
                                `funct==`DIVU)
                                )?1:0;

	 assign Mop = (`funct==`MULT)?  2'b00 :
	              (`funct==`MULTU)? 2'b01 :
	              (`funct==`DIV)?   2'b10 :
                                   2'b11 ;  //DIVU

    assign MDCmd = (`op==`R && (`funct==`MFLO || `funct==`MFHI ||
                                `funct==`MTLO || `funct==`MTHI ||
                                `funct==`MULT || `funct==`MULTU ||
                                `funct==`DIV || `funct==`DIVU
                                ))?1:0;

    assign HLWr = (`op==`R && (`funct==`MTLO || `funct==`MTHI))?1:0;

    assign MDDst = (`funct==`MTHI)?1:0;

    assign HLSrc = (`funct==`MFHI)?1:0;

    // DM
    assign Dop = (`op == `LW) ?      3'b000:
                 (`op == `LH) ?      3'b001:
                 (`op == `LHU) ?     3'b010:
                 (`op == `LB) ?      3'b011:
                 (`op == `LBU) ?     3'b100:
                                     0;
    assign ld = (`op == `LW || `op == `LH || `op == `LHU || `op == `LB || `op == `LBU);

    assign store = (`op == `SW)?     2'b00:
                   (`op == `SH)?     2'b01:
                   (`op == `SB)?     2'b10:
                                     0;
    assign st = (`op == `SW || `op == `SH || `op == `SB);

    assign MemWr = (`op==`SW || `op==`SH || `op==`SB);

    // CMP
    assign Cop = (`op==`BEQ)?        3'b000:
                 (`op==`BNE)?        3'b001:
                 (`op==`BLEZ)?       3'b010:
                 (`op==`BGTZ)?       3'b011:             
                 (`op==`BLTZ)?       (3'b100 + instr[`RT]):
                                     3'b110;
////////////////////////////////////////////////

    assign shmt = (`op==`R &&(`funct==`SLL ||
                             `funct==`SRL ||
                             `funct==`SRA)
                             );
///////////////////////////////////////////////////////

    assign RinSel = (`op==`R && (`funct==`ADDU || `funct==`ADD  ||
                                 `funct==`SLL  || `funct==`SRL  ||
                                 `funct==`SRA  || `funct==`SLLV ||
                                 `funct==`SRLV || `funct==`SRAV ||
                                 `funct==`SUBU || `funct==`SUB  ||
                                 `funct==`SLT  || `funct==`SLTU ||
                                 `funct==`AND  || `funct==`OR   ||
                                 `funct==`XOR  || `funct==`NOR  ||
                                 `funct==`NOR  ) ||
                         `op==`ORI    || `op==`ADDI ||
                         `op==`ADDIU  || `op==`ANDI ||
                         `op==`XORI   || `op==`SLTI ||
                         `op==`SLTIU  || `op==`LUI )?      
        /*/ ALURes  */           3'b000 :   
                    (`op==`LW || `op==`LB || `op==`LBU || `op==`LH || `op==`LHU)?
        /*/ DM      */           3'b001 :   
                    (`op==`R && (`funct==`MFHI || `funct==`MFLO))?
        /*/ MDU     */           3'b010 :   
                    (`op==`R && `funct==`JALR || `op==`JAL)?
        /*/ PC + 8  */           3'b011 :
                    (`op==`COP0 && instr[`RS]==`MFC0)?
        /*/ CP0     */           3'b100 :
        /*/ Default */           3'b111 ;
///////////////////////////////////////////////////////////

    assign RegWr = (`op==`ORI   || `op==`ADDI || `op==`ADDIU ||
                    `op==`ANDI  || `op==`XORI || `op==`SLTI  ||
                    `op==`SLTIU || `op==`LW   || `op==`LB    ||
                    `op==`LBU   || `op==`LH   || `op==`LHU   ||
                    `op==`LUI   || `op==`JAL  || 
                    `op==`R && (`funct==`ADDU || `funct==`ADD  ||
                                `funct==`SLL  || `funct==`SRL  ||
                                `funct==`SRA  || `funct==`SLLV ||
                                `funct==`SRLV || `funct==`SRAV ||
                                `funct==`SUBU || `funct==`SUB  ||
                                `funct==`SLT  || `funct==`SLTU ||
                                `funct==`AND  || `funct==`OR   ||
                                `funct==`XOR  || `funct==`NOR  ||
                                `funct==`JALR || `funct==`MFHI ||
                                `funct==`MFLO)||
                    `op==`COP0 && instr[`RS]==`MFC0);
////////////////////////////////////////////////////////////////////////

    assign RegDst = (`op==`ORI   || `op==`ADDI || `op== `ADDIU ||
                     `op==`ANDI  || `op==`XORI || `op== `SLTI  ||
                     `op==`SLTIU || `op==`LW   || `op== `LB    ||
                     `op==`LBU   || `op==`LH   || `op== `LHU   ||
                     `op==`LUI||
                     `op==`COP0 && instr[`RS]==`MFC0)?
        /*/ GRF[rt] */            2'b00 :
                    (`op==`R && (`funct==`ADDU || `funct==`ADD  ||
                                 `funct==`SLL  || `funct==`SRL  ||
                                 `funct==`SRA  || `funct==`SLLV ||
                                 `funct==`SRLV || `funct==`SRAV ||
                                 `funct==`SUBU || `funct==`SUB  ||
                                 `funct==`SLT  || `funct==`SLTU ||
                                 `funct==`AND  || `funct==`OR   ||
                                 `funct==`XOR  || `funct==`NOR  ||
                                 `funct==`JALR || `funct==`MFHI ||
                                 `funct==`MFLO))?
        /*/ GRF[rd] */            2'b01 :
                    (`op==`JAL)?
        /*/  $ra    */            2'b10 :
        /*/ Default */            2'b11 ;
///////////////////////////////////////////////////

    assign PCSrc = (`op==`BEQ || `op==`BNE || `op==`BLEZ || `op==`BGTZ || `op==`BLTZ)? //BGEZ
        /*/Branch (CMP) */        2'b01 :
                   (`op==`J || `op==`JAL)?
        /*/ imm32   */            2'b10 :
                   (`op==`R && (`funct==`JR || `funct==`JALR))?
        /*/ GRF[rs] */            2'b11 :
        /*/ PC + 4  */            2'b00 ;
///////////////////////////////////////////////////////

    assign Eop = (`op==`ORI || `op==`ANDI || `op==`XORI)?
        /*/ Unsigned*/            2'b00 :
                 (`op==`ADDI  || `op==`ADDIU || `op==`SLTI ||
                  `op==`SLTIU || `op==`LW    || `op==`LB   ||
                  `op==`LBU   || `op==`LH    || `op==`LHU  ||
                  `op==`SW    || `op==`SB    || `op==`SH)?
        /*/ Signed  */            2'b01 :
                 (`op==`LUI)?
        /*/ LUI     */            2'b10 :
        /*/ Default */            2'b11 ;
///////////////////////////////////////////////////////////////

    assign ASrc = (`op==`ORI   || `op==`ADDI || `op==`ADDIU ||
                   `op==`ANDI  || `op==`XORI || `op==`SLTI  ||
                   `op==`SLTIU || `op==`LW   || `op==`LB    ||
                   `op==`LBU   || `op==`LH   || `op==`LHU   ||
                   `op==`SW    || `op==`SB   || `op==`SH    ||
                   `op==`LUI);

    assign Aop = (`op==`R && `funct==`SUBU)?                     4'b0001:
                 (`op==`ORI || `op==`R && `funct==`OR)?          4'b0010:
                 (`op==`R &&(`funct==`SLL || `funct==`SLLV))?    4'b0011:
                 (`op==`R &&(`funct==`SRL || `funct==`SRLV))?    4'b0100:
                 (`op==`R &&(`funct==`SRA || `funct==`SRAV))?    4'b0101:
                 (`op==`ANDI || `op==`R && `funct==`AND)?        4'b0110:
                 (`op==`XORI || `op==`R && `funct==`XOR)?        4'b0111:
                 (`op==`R && `funct==`NOR)?                      4'b1000:
                 (`op==`SLTI || `op==`R && `funct==`SLT)?        4'b1001:
                 (`op==`SLTIU || `op==`R && `funct==`SLTU)?      4'b1010:
                 (`op==`ADDI || `op==`R && `funct==`ADD || 
                  `op==`LW || `op==`LB || `op==`LBU || `op==`LH || `op==`LHU ||
                  `op==`SW || `op==`SH || `op==`SB)?             4'b1011:
                 (`op==`R && `funct==`SUB)?                      4'b1100:
                                                                 4'b0000;
    assign CP0Wr = (`op==`COP0 && instr[`RS]==`MTC0);
    assign eret = (`op==`COP0 && `funct==`ERET);

endmodule
